using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Legend.Threading;

namespace Legend.Collections
{
    /// <summary>
    /// Wraps anohter IEnumerator to synchronize the access by holding
    /// a read lock on the specified IReaderWriterLock.
    /// </summary>
    /// <typeparam name="T">The type of items to enumerate.</typeparam>
    public class LockingEnumerator<T>
            : IEnumerator<T>
    {
        
        private IEnumerator<T> enumerator;
        private ISynchronizationManager synchronizationManager; 
        

        
        /// <summary>
        /// Initializes a new instance of the <see cref="LockingEnumerator&lt;T&gt;"/> class.
        /// </summary>
        /// <param name="enumerator">The enumerator.</param>
        /// <param name="readerWriterLock">The reader writer lock.</param>
        public LockingEnumerator(IEnumerator<T> enumerator, ISynchronizationManager readerWriterLock)
        {
            Require.ThatArgument(enumerator).Named("enumerator").IsNotNull();
            Require.ThatArgument(readerWriterLock).Named("readerWriterLock").IsNotNull();
            
            this.enumerator = enumerator;
            this.synchronizationManager = readerWriterLock;

            this.synchronizationManager.EnterReadLock();
        } 
        

        
        /// <summary>
        /// Gets the element in the collection at the current position of the enumerator.
        /// </summary>
        /// <value></value>
        /// <returns>
        /// The element in the collection at the current position of the enumerator.
        /// </returns>
        public T Current
        {
            get
            {
                return enumerator.Current;
            }
        }

        /// <summary>
        /// Gets the element in the collection at the current position of the enumerator.
        /// </summary>
        /// <value></value>
        /// <returns>
        /// The element in the collection at the current position of the enumerator.
        /// </returns>
        object System.Collections.IEnumerator.Current
        {
            get
            {
                return enumerator.Current;
            }
        }
        

        
        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            enumerator.Dispose();
            synchronizationManager.ExitReadLock();
        }

        /// <summary>
        /// Advances the enumerator to the next element of the collection.
        /// </summary>
        /// <returns>
        /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection.
        /// </returns>
        /// <exception cref="T:System.InvalidOperationException">
        /// The collection was modified after the enumerator was created.
        /// </exception>
        public bool MoveNext()
        {
            return enumerator.MoveNext();
        }

        /// <summary>
        /// Sets the enumerator to its initial position, which is before the first element in the collection.
        /// </summary>
        /// <exception cref="T:System.InvalidOperationException">
        /// The collection was modified after the enumerator was created.
        /// </exception>
        public void Reset()
        {
            enumerator.Reset();
        } 
        
    }
}
